1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkArgument;
20  import static com.google.common.base.Preconditions.checkNotNull;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.annotations.GwtIncompatible;
24  
25  import java.io.IOException;
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutputStream;
28  import java.util.EnumMap;
29  import java.util.Map;
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  @GwtCompatible(emulated = true)
44  public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
45      extends AbstractBiMap<K, V> {
46    private transient Class<K> keyType;
47    private transient Class<V> valueType;
48  
49    
50  
51  
52  
53  
54  
55  
56    public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
57        create(Class<K> keyType, Class<V> valueType) {
58      return new EnumBiMap<K, V>(keyType, valueType);
59    }
60  
61    
62  
63  
64  
65  
66  
67  
68  
69  
70  
71    public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
72        create(Map<K, V> map) {
73      EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
74      bimap.putAll(map);
75      return bimap;
76    }
77  
78    private EnumBiMap(Class<K> keyType, Class<V> valueType) {
79      super(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
80          WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
81      this.keyType = keyType;
82      this.valueType = valueType;
83    }
84  
85    static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
86      if (map instanceof EnumBiMap) {
87        return ((EnumBiMap<K, ?>) map).keyType();
88      }
89      if (map instanceof EnumHashBiMap) {
90        return ((EnumHashBiMap<K, ?>) map).keyType();
91      }
92      checkArgument(!map.isEmpty());
93      return map.keySet().iterator().next().getDeclaringClass();
94    }
95  
96    private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
97      if (map instanceof EnumBiMap) {
98        return ((EnumBiMap<?, V>) map).valueType;
99      }
100     checkArgument(!map.isEmpty());
101     return map.values().iterator().next().getDeclaringClass();
102   }
103 
104   
105   public Class<K> keyType() {
106     return keyType;
107   }
108 
109   
110   public Class<V> valueType() {
111     return valueType;
112   }
113 
114   @Override
115   K checkKey(K key) {
116     return checkNotNull(key);
117   }
118 
119   @Override
120   V checkValue(V value) {
121     return checkNotNull(value);
122   }
123 
124   
125 
126 
127 
128   @GwtIncompatible("java.io.ObjectOutputStream")
129   private void writeObject(ObjectOutputStream stream) throws IOException {
130     stream.defaultWriteObject();
131     stream.writeObject(keyType);
132     stream.writeObject(valueType);
133     Serialization.writeMap(this, stream);
134   }
135 
136   @SuppressWarnings("unchecked") 
137   @GwtIncompatible("java.io.ObjectInputStream")
138   private void readObject(ObjectInputStream stream)
139       throws IOException, ClassNotFoundException {
140     stream.defaultReadObject();
141     keyType = (Class<K>) stream.readObject();
142     valueType = (Class<V>) stream.readObject();
143     setDelegates(
144         WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
145         WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
146     Serialization.populateMap(this, stream);
147   }
148 
149   @GwtIncompatible("not needed in emulated source.")
150   private static final long serialVersionUID = 0;
151 }